
<template>
    <canvas :width="width" :height="height" ref="canvasRef"></canvas>
    <br>
    <div>{{ timeLabel }}</div>
</template>
<script lang="ts">
export default {
    name: "时钟",
};
</script>
<script setup lang="ts">
import { ref, onMounted, computed } from "vue";
import * as GLMatrix from "gl-matrix";
import { getCirclePoint } from '../../util/Util'
const width = ref<number>(600);
const height = ref<number>(600);
const canvasRef = ref<HTMLCanvasElement>();
const webgl = ref<WebGLRenderingContext>();
const programV = ref<WebGLProgram>();
const transition = ref(GLMatrix.mat4.create());
const SLen = ref(160);
const MLen = ref(120);
const HLen = ref(80);
const timeLabel = ref<string>('');

const veSoure = computed(() => {
    return `
          uniform mat4 viewP;
          uniform mat4 trans;
          attribute vec4 point;
          attribute vec4 color;
    
          varying vec4 t_color;
          void main(void){
            gl_Position = trans * viewP * point;
            gl_PointSize = 1.0;
            t_color = color;
          }
    
        `;
});

const veShader = computed(() => {
    const gl = webgl.value;
    if (!gl) return;
    const shader = gl.createShader(gl.VERTEX_SHADER);
    if (!shader) return;
    gl.shaderSource(shader, veSoure.value);
    gl.compileShader(shader);
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        var info = gl.getShaderInfoLog(shader);
        throw "Could not compile WebGL program. \n\n" + info;
    }
    return shader;
});

const frSource = computed(() => {
    return `
        precision mediump float;
        varying vec4 t_color;
        void main(void){
            gl_FragColor = vec4(t_color.x , t_color.y , t_color.z ,1.0);
            // gl_FragColor = vec4(1,0,0,1.0);
        }
        `;
});

const viewValue = computed(() => {
    const value = GLMatrix.mat4.create();
    GLMatrix.mat4.ortho(value, 0, width.value, height.value, 0, -1, 1);
    return value;
});

const frShader = computed(() => {
    const gl = webgl.value;
    if (!gl) return;
    const shader = gl.createShader(gl.FRAGMENT_SHADER);
    if (!shader) return;
    gl.shaderSource(shader, frSource.value);
    gl.compileShader(shader);
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        var info = gl.getShaderInfoLog(shader);
        throw "Could not compile WebGL program. \n\n" + info;
    }
    return shader;
});

onMounted(() => {
    const gl = canvasRef.value?.getContext("webgl");
    if (!gl) return;
    webgl.value = gl;
    if (!veShader.value) return;
    if (!frShader.value) return;

    const program = gl.createProgram();
    if (!program) return;
    programV.value = program;
    gl.attachShader(program, veShader.value);
    gl.attachShader(program, frShader.value);
    gl.linkProgram(program);
    gl.useProgram(program);

    const viewP = gl.getUniformLocation(program, "viewP");
    gl.uniformMatrix4fv(viewP, false, viewValue.value);

    const trans = gl.getUniformLocation(program, "trans");
    gl.uniformMatrix4fv(trans, false, transition.value);

    const points = new Float32Array([
        0,
        0,
        1,
        0,
        0,
        HLen.value,
        0,
        1,
        0,
        0,
        HLen.value,
        12,
        1,
        0,
        0,
        0,
        12,
        1.0,
        0,
        0,
        0,
        0,
        0,
        1,
        0,
        MLen.value,
        0,
        0,
        1,
        0,
        MLen.value,
        6,
        0,
        1,
        0,
        0,
        6,
        0.0,
        1,
        0,
        0,
        0,
        0,
        0,
        1,
        SLen.value,
        0,
        0,
        0,
        1,
        SLen.value,
        4,
        0,
        0,
        1,
        0,
        4,
        0,
        0,
        1,
        ...getCirclePoint(100, { center: { x: 0, y: 0 }, radius: 10, pointL: 2, color: [1, 0, 0] })
    ]);
    const pBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, pBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

    const pointV = gl.getAttribLocation(program, "point");
    gl.enableVertexAttribArray(pointV);
    gl.vertexAttribPointer(
        pointV,
        2,
        gl.FLOAT,
        false,
        points.BYTES_PER_ELEMENT * 5,
        0
    );

    const colorV = gl.getAttribLocation(program, "color");
    gl.enableVertexAttribArray(colorV);
    gl.vertexAttribPointer(
        colorV,
        3,
        gl.FLOAT,
        false,
        points.BYTES_PER_ELEMENT * 5,
        points.BYTES_PER_ELEMENT * 2
    );

    render();
});

const getMat2 = (rectHeight: number, rotate: number, bb = 30) => {
    const _width = width.value / 2;
    const _height = height.value / 2;
    const rMat1 = GLMatrix.mat4.create();
    GLMatrix.mat4.rotate(rMat1, rMat1, rotate, [0, 0, -1]);

    const tMat2 = GLMatrix.mat4.create();
    GLMatrix.mat4.translate(tMat2, tMat2, [
        (_width - bb) / _width,
        -(_height - rectHeight / 2) / _height,
        0,
    ]);
    const re = GLMatrix.mat4.create();
    GLMatrix.mat4.multiply(re, rMat1, tMat2);
    // 坐标系为webgl
    //【先平移和旋转】 == 旋转矩阵*(平移矩阵 * 点) 
    //【先旋转和平移】 == 平移矩阵*(旋转矩阵 * 点) 
    return re;
};

const render = () => {
    const gl = webgl.value;
    const program = programV.value;
    if (!gl || !program) return;

    const trans = gl.getUniformLocation(program, "trans");
    const _render = () => {
        gl.clearColor(0, 0, 0, 1);
        gl.clear(gl.COLOR_BUFFER_BIT);
        const nowTime = new Date();
        const HH = nowTime.getHours();
        const MM = nowTime.getMinutes();
        const SS = nowTime.getSeconds();
        timeLabel.value = `${HH}:${MM}:${SS}`
        gl.uniformMatrix4fv(
            trans,
            false,
            getMat2(12, (HH / 24) * Math.PI * 2 - Math.PI / 2)
        );
        gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
        gl.uniformMatrix4fv(
            trans,
            false,
            getMat2(8, (MM / 60) * Math.PI * 2 - Math.PI / 2)
        );
        gl.drawArrays(gl.TRIANGLE_FAN, 4, 4);
        gl.uniformMatrix4fv(
            trans,
            false,
            getMat2(6, (SS / 60) * Math.PI * 2 - Math.PI / 2)
        );
        gl.drawArrays(gl.LINE_LOOP, 8, 4);

        //
        const cirValue = GLMatrix.mat4.create();
        GLMatrix.mat4.translate(cirValue, cirValue, [1, -1, 0])
        gl.uniformMatrix4fv(
            trans,
            false,
            cirValue
        );
        gl.drawArrays(gl.TRIANGLE_FAN, 12, 100);
        requestAnimationFrame(_render);
    };
    requestAnimationFrame(_render);
};
</script>
  
<style></style>
  